package com.gitee.wsl.android.ui.ext

import android.view.View
import android.widget.ImageButton
import androidx.core.view.ViewCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.Lifecycle
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.adapter.FragmentStateAdapter
import androidx.viewpager2.widget.ViewPager2
import com.gitee.wsl.android.ext.math.dp
import com.google.android.material.tabs.TabLayout

/**
 * A simple wrapper for [OnPageChangeCallback] to tell which page is showing or gone
 * @param block a lambda to tell the page visibility change
 */
fun ViewPager2.onPageVisibilityChange(block: (index: Int, isVisible: Boolean) -> Unit) {
    var lastPage: Int = currentItem
    val listener = object : ViewPager2.OnPageChangeCallback() {
        override fun onPageSelected(position: Int) {
            if (lastPage != position) {
                block(lastPage, false)
            }
            block(position, true)
            lastPage = position
        }
    }
    registerOnPageChangeCallback(listener)
    addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
        override fun onViewAttachedToWindow(v: View) {
        }

        override fun onViewDetachedFromWindow(v: View) {
            if (v == null || v !is ViewPager2) return
            if (ViewCompat.isAttachedToWindow(v)) {
                v.unregisterOnPageChangeCallback(listener)
            }
            removeOnAttachStateChangeListener(this)
        }

    })
}

fun FragmentActivity.FragmentStateAdapter(vararg fragments: Fragment, isLazyLoading: Boolean = false): FragmentStateAdapter =
    FragmentStateAdapter(fragments.size, isLazyLoading) { fragments[it] }

fun Fragment.FragmentStateAdapter(vararg fragments: Fragment, isLazyLoading: Boolean = false): FragmentStateAdapter =
    FragmentStateAdapter(fragments.size, isLazyLoading) { fragments[it] }

fun FragmentActivity.FragmentStateAdapter(itemCount: Int, isLazyLoading: Boolean = false, block: (Int) -> Fragment): FragmentStateAdapter =
    FragmentStateAdapter(supportFragmentManager, lifecycle, itemCount, isLazyLoading, block)

fun Fragment.FragmentStateAdapter(itemCount: Int, isLazyLoading: Boolean = false, block: (Int) -> Fragment): FragmentStateAdapter =
    FragmentStateAdapter(childFragmentManager, lifecycle, itemCount, isLazyLoading, block)

fun FragmentStateAdapter(
    fragmentManager: FragmentManager,
    lifecycle: Lifecycle,
    itemCount: Int,
    isLazyLoading: Boolean = false,
    block: (Int) -> Fragment
) =
    object : FragmentStateAdapter(fragmentManager, lifecycle) {
        override fun getItemCount() = itemCount
        override fun createFragment(position: Int) = block(position)
        override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
            super.onAttachedToRecyclerView(recyclerView)
            if (isLazyLoading) recyclerView.setItemViewCacheSize(itemCount)
        }
    }

@Suppress("UNCHECKED_CAST")
fun <T : Fragment> ViewPager2.findFragment(fragmentManager: FragmentManager, position: Int) =
    fragmentManager.findFragmentByTag("f$position") as T?


/**
 * Animating the view pager indicator with image button close.
 * When user swipe to last page on view pager, indicator will hide and image button show's up.
 */
class AnimateViewPagerIndicator(
    private val lastPage: Int,
    private val tabLayout: TabLayout,
    private val imageButton: ImageButton
) {

    companion object {
        private var isImageButtonGoToHomeShowing = false
        private const val AnimationDurationForButtonGo = 800L
        private const val AnimationDurationForTranslation = 800L
        private const val AnimationDurationForAlpha = 500L
        private const val FullAlpha = 1F
        private const val ZeroAlpha = 0F
        private val ImageButtonGoToHomeSize = 58.dp
        private val TranslationXImageButtonGotToHome = (-75F).dp
        private const val TranslationXShow = 0f
        private val TranslationXHideTabIndicator = (20f).dp
        private const val StartHeightZero = 0
        private const val StartWithZero = 0
    }

    fun animateView(position: Int) {
        if (position == lastPage) {
            hideIndicator()
        } else {
            if (isImageButtonGoToHomeShowing)
                showIndicator()
        }
    }

    private fun hideIndicator() {
        isImageButtonGoToHomeShowing = true
        animationTabIndicatorHide()
        animationImageButtonGotToHomeScaleUp()
    }

    private fun showIndicator() {
        isImageButtonGoToHomeShowing = false
        animationTabIndicatorShow()
        animationImageButtonGotToHomeScaleDown()
    }

    /**
     * Hide tab indicator with animation
     */
    private fun animationTabIndicatorHide() {
        tabLayout.animate().translationX(TranslationXHideTabIndicator).duration =
            AnimationDurationForTranslation
        tabLayout.animate().alpha(ZeroAlpha).duration =
            AnimationDurationForAlpha
    }

    /**
     * Increase with and height of image button go, with animation
     */
    private fun animationImageButtonGotToHomeScaleUp() {
        imageButton.animate().translationX(TranslationXShow)
            .duration = AnimationDurationForTranslation
        val animation = ResizeAnimation(
            imageButton,
            ImageButtonGoToHomeSize, StartHeightZero, ImageButtonGoToHomeSize, StartWithZero, false
        )
        animation.duration = AnimationDurationForButtonGo
        imageButton.startAnimation(animation)
    }

    /**
     * Show tab indicator with animation
     */
    private fun animationTabIndicatorShow() {
        tabLayout.animate().translationX(TranslationXShow).duration =
            AnimationDurationForTranslation
        tabLayout.animate().alpha(FullAlpha).duration =
            AnimationDurationForAlpha
    }

    /**
     * Decrease with and height of image button go, with animation
     */
    private fun animationImageButtonGotToHomeScaleDown() {
        imageButton.animate()
            .translationX(TranslationXImageButtonGotToHome).duration =
            AnimationDurationForTranslation
        val animation = ResizeAnimation(
            imageButton,
            ImageButtonGoToHomeSize,
            ImageButtonGoToHomeSize,
            ImageButtonGoToHomeSize,
            ImageButtonGoToHomeSize,
            true
        )
        animation.duration = AnimationDurationForButtonGo
        imageButton.startAnimation(animation)
    }
}
